package com.um.jdy.app.device.manager;

import cn.hutool.core.util.StrUtil;
import com.um.jdy.app.core.manager.OrderRedisTemplate;
import com.um.jdy.app.charge.manager.EBOrderManager;
import com.um.jdy.common.alarm.service.AlarmRecordService;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.charge.entity.po.EbOrder;
import com.um.jdy.common.charge.entity.po.Order;
import com.um.jdy.common.charge.entity.po.OrderPower;
import com.um.jdy.common.charge.enums.OrderAction;
import com.um.jdy.common.charge.enums.OrderEnum;
import com.um.jdy.common.charge.service.EbOrderService;
import com.um.jdy.common.charge.service.OrderPowerService;
import com.um.jdy.common.charge.service.OrderService;
import com.um.jdy.common.device.entity.po.PortAlarmRecord;
import com.um.jdy.common.device.entity.po.Gun;
import com.um.jdy.common.device.entity.po.Pile;
import com.um.jdy.common.device.enums.DeviceEnum;
import com.um.jdy.common.device.service.*;
import com.um.jdy.common.push.service.PushService;
import com.um.jdy.rpc.api.RpcEBDeviceService;
import com.um.jdy.rpc.entity.EBDevice;
import com.um.jdy.rpc.entity.EBDeviceInfo;
import com.um.jdy.rpc.entity.EBPort;
import com.um.jdy.rpc.enums.*;
import com.um.jdy.rpc.factory.ServiceFactory;
import com.um.jdy.rpc.notify.RpcEBDeviceNotifyService;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.utils.IdUtils;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.OrderUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.springcloud.dubbo.cluster.DeviceKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 电单车设备处理逻辑
 * @Description
 * @Author dnannhui
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
@DubboService
public class EBDeviceManager implements RpcEBDeviceNotifyService {

    @Autowired
    PileService pileService;

    @Autowired
    GunService gunService;

    @Autowired
    OrderService orderService;

    @Autowired
    EbOrderService ebOrderService;

    @Autowired
    OrderPowerService orderPowerService;

    @Autowired
    ServiceFactory serviceFactory;

    @Autowired
    EBOrderManager ebOrderManager;

    @Autowired
    OnlineLogService onlineLogService;

    @Autowired
    PortAlarmRecordService portAlarmRecordService;

    @Autowired
    AlarmRecordService alarmRecordService;

    @Autowired
    OrderRedisTemplate orderRedisTemplate;

    @Autowired
    PushService pushService;

    /**
     * 设备登录上报
     *
     * @param seq        序列号
     * @param imei IMEI码
     * @param ports      端口列表
     * @param info       设备信息
     */
    @Override
    public void reqDeviceLogin(String cmd, String seq, String imei, List<EBPort> ports, EBDeviceInfo info) {

        try {
            info.setHeart(60);
            serviceFactory.getRpcEBDeviceService(info.getProtocol()).respDeviceLogin(seq,new DeviceKey(imei),info);
        }catch (Exception ex){
            log.error("回复失败-Cmd00LoginReq", ex);
        }

        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        onlineLogService.addOnline(devicePile.getCode(),devicePile.getName());

        //更新端口状态
        updatePortsStatus(devicePile.getDevicePileId(),ports);

        //修改为在线状态,上报状态正常,更新上线时间
        devicePile.setRssi(info.getRssi());
        devicePile.setIccid(info.getIccid());
        devicePile.setVersion(info.getVersion());
        devicePile.setOpenState(DeviceEnum.OpenStatus.Enable.name());
        devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
        devicePile.setLastOnlineTime(new Date());
        devicePile.setIpAddress(info.getIpAddress());
        devicePile.setProtocol(info.getProtocol());
        if(devicePile.getParameters() == null || StrUtil.isEmpty(devicePile.getParameters())){
            WireEnum ebType = WireEnum.valueOf(StringUtil.getTrim(info.getEbType(),WireEnum.Wired.name()));
            if(ebType == null)
                ebType = WireEnum.Wired;
            devicePile.setParameters(serviceFactory.getEBDeviceParameters(info.getProtocol(),ebType));
        }
        pileService.updateRow(devicePile);


    }

    /**
     * 设备离线上报
     *
     * @param imei IMEI码
     */
    @Override
    public void reqDeviceOffline(String imei) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        //推送
        pushService.pushDeviceOffline(devicePile);
    }

    /**
     * 设备心跳上报
     *
     * @param seq        序列号
     * @param imei IMEI码
     * @param ports      端口列表
     * @param info       设备信息
     */
    @Override
    @Transactional
    public void reqDeviceHeart(String cmd, String seq, String imei, List<EBPort> ports, EBDeviceInfo info) {

        try {
            serviceFactory.getRpcEBDeviceService(info.getProtocol()).respDeviceHeart(seq,new DeviceKey(imei));
        }catch (Exception ex){
            log.error("回复失败-Cmd01HeartResp", ex);
        }

        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        devicePile.setProtocol(info.getProtocol());
        pileService.updateRow(devicePile);

        //更新端口状态
        updatePortsStatus(devicePile.getDevicePileId(),ports);

        //当comId为空时，属于厂商测试，不需要处理数据
        if(StringUtil.isEmpty(devicePile.getComId()))
            return;

        //键思研或友电的不用处理下面的数据
        if (info.getProtocol().equals(DeviceProtocolEnum.JSY_TCP_10.getKey()) || info.getProtocol().equals(DeviceProtocolEnum.YD_SDK_10.getKey())
                || info.getProtocol().equals(DeviceProtocolEnum.PZ_MQTT_10.getKey()))
            return;

        updateChargingData(devicePile,info.getRssi(),info.getTemp(),ports,info.getProtocol());
    }

    /**
     * 实时上报充电数据(健思研才有)
     * @param seq 序列号
     * @param imei IMEI码
     * @param ports 端口列表
     * @param device 充电总数据
     */
    @Override
    public void reqChargingData(String command,String seq, String imei, String protocol,List<EBPort> ports, EBDevice device){
        try {
            serviceFactory.getRpcEBDeviceService(protocol).respChargingData(seq,new DeviceKey(imei));
        }catch (Exception ex){
            log.error("回复失败-Cmd08ChargingDataResp", ex);
        }


        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        //当comId为空时，属于厂商测试，不需要处理数据
        if(StringUtil.isEmpty(devicePile.getComId()))
            return;

        updateChargingData(devicePile,null,device.getTemp(),ports,protocol);
    }

    /**
     * 设备物联网状态上报
     *
     * @param imei
     * @param status
     */
    @Override
    public void reqDeviceIotStatus(String imei, DeviceIotEnum status) {
        log.info("设备[{}]上报物联状态[{}]", imei, status.getValue());
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile != null || status == DeviceIotEnum.ONLINE) {
            devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
            devicePile.setHeartTime(new Date());
            pileService.updateRow(devicePile);
        }
    }

    @Override
    public void reqException(String imei, Integer port, EBExceptionEnum exception) {
        Pile devicePile = pileService.getRow("imei", imei);
        if (devicePile != null) {
            PortAlarmRecord record = new PortAlarmRecord();
            record.setDevicePileId(devicePile.getDevicePileId());
            record.setComId(devicePile.getComId());
            record.setCode(devicePile.getCode());
            record.setDeviceType(DeviceTypeEnum.EB.name());
            record.setImei(devicePile.getImei());
            record.setGunNum(port);
            record.setAlarmCode(exception.name());
            record.setCreateTime(new Date());
            portAlarmRecordService.addRow(record);

            try{
                Gun gun = gunService.getRow(new String[]{"device_pile_id","port"},new Object[]{devicePile.getDevicePileId(),port});
                if(gun != null) {
                    alarmRecordService.add(devicePile.getDeviceStationId(), devicePile.getDevicePileId(), gun.getDeviceGunId(),
                            exception.name(), null);
                }
            }catch (Exception e){
                log.error("设备[{}]故障上报错误", imei, e);
            }
        }
    }

    @Override
    public void reqRemoveException(String imei, Integer port, EBExceptionEnum exception) {
        PortAlarmRecord record = portAlarmRecordService.getRow( new String[]{"imei", "gun_num", "alarm_code", "status"},
                new Object[]{imei, port, exception.name(), YesOrNo.No.name()});
        if (record != null) {
            record.setStatus(YesOrNo.Yes.name());
            portAlarmRecordService.saveRow(record);
        }
    }

    /**
     * 回复端口状态查询
     *
     * @param seq        序列号
     * @param imei IMEI码
     * @param ports      端口列表
     */
    @Override
    public void respQueryPorts(String cmd, String seq, String imei, List<EBPort> ports) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        if(!devicePile.getDeviceStatus().equals(DeviceEnum.DeviceStatus.Online.name())) {
            devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
            devicePile.setHeartTime(new Date());
            pileService.updateRow(devicePile);
        }

        updatePortsStatus(devicePile.getDevicePileId(),ports);
    }

    /**
     * 回复语音播放
     *
     * @param seq        序列号
     * @param imei IMEI码
     */
    @Override
    public void respPlayTTS(String cmd, String seq, String imei) {

    }

    /**
     * 回复设备重启
     *
     * @param seq        序列号
     * @param imei IMEI码
     */
    @Override
    public void respRestart(String cmd, String seq, String imei) {

    }

    /**
     * 回复参数设置
     *
     * @param seq        序列号
     * @param imei IMEI码
     */
    @Override
    public void respSetParams(String cmd, String seq, String imei) {
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile != null) {
            devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
            devicePile.setHeartTime(new Date());
            pileService.updateRow(devicePile);
        }
    }

    /**
     * 更新端口的状态
     * @param devicePileId
     * @param ports
     */
    private void updatePortsStatus(String devicePileId,List<EBPort> ports){
        List<Gun> listGun = gunService.getRows("device_pile_id",devicePileId,"port","asc");
        for(Gun gun : listGun){
            for(EBPort port : ports){
                if(gun.getPort() == port.getPort()){
//                    if(port.getState() <= 1) {//0 端口关闭，1 端口输出
//                        gun.setStatus(port.getState() == 0?DeviceEnum.PortStatus.Available.name():DeviceEnum.PortStatus.Charging.name());
//                    }else if(port.getState() == 6){//6 端口异常
//                        gun.setStatus(DeviceEnum.PortStatus.Faulted.name());
//                    }else{//2 输出时间到，3 充电完成，4 插头拨出，5 功率过大，7高温报警
//                        log.debug("插座状态为2 输出时间到，3 充电完成，4 插头拨出，5 功率过大，7高温报警 暂不处理：{}",port.getState());
//                        gun.setStatus(DeviceEnum.PortStatus.Available.name());
//                    }
                    gun.setStatus(port.getState());
                    if(!gun.getStatus().equals(DeviceEnum.PortStatus.Charging.name())){
                        gun.setOrderNo("");
                    }
                    gunService.updateRow(gun);
                    break;
                }
            }
        }
    }

    /**
     * 充电实时数据
     * @param devicePile
     * @param rssi
     * @param temp
     * @param ports
     */
    private void updateChargingData(Pile devicePile,Integer rssi,Integer temp,List<EBPort> ports,String protocol){
        devicePile.setDeviceStatus(DeviceEnum.DeviceStatus.Online.name());
        devicePile.setRssi(rssi);
        devicePile.setTemp(temp);
        devicePile.setProtocol(protocol);
        devicePile.setHeartTime(new Date());
        pileService.updateRow(devicePile);

       // updatePortsStatus(devicePile.getDevicePileId(),ports);

        for (EBPort port : ports) {
            //端口空闲情况下，通过redis判断有充电中订单，再查询数据库
            if (port.getState().equals(DeviceEnum.PortStatus.Available.name()) &&
                    !StringUtil.isEmpty(orderRedisTemplate.getOrder(devicePile.getCode(),port.getPort(),OrderEnum.Status.Charging))) {
                Order notStopOrder = orderService.getRow(orderRedisTemplate.getOrder(devicePile.getCode(),port.getPort(),OrderEnum.Status.Charging));

                //修复订单状态:添加心跳5次都是空闲，才会结束，有时候设备状态上报有问题
                if (notStopOrder != null && orderRedisTemplate.isPortFree(notStopOrder.getDeviceCode(),notStopOrder.getPort())) {
                    try {
                        ebOrderManager.stopChargeByHeart(notStopOrder.getOrderNo());
                    } catch (Exception ex) {

                        orderRedisTemplate.removeChargeFull(notStopOrder.getChargeOrderId());
                        orderRedisTemplate.removePortFree(devicePile.getCode(), port.getPort());
                        orderRedisTemplate.removeOrder(devicePile.getCode(),port.getPort());
                        log.error("设备停止，订单未停止：", ex);
                    }
                }
            }

            if (port.getState().equals(DeviceEnum.PortStatus.Charging.name())) {

                orderRedisTemplate.removePortFree(devicePile.getCode(),port.getPort());

                //先访问redis有未启订单，再查询数据库
                if(!StringUtil.isEmpty(orderRedisTemplate.getOrder(devicePile.getCode(), port.getPort(), OrderEnum.Status.NotStarted))){
                    Order notStartOrder = orderService.getRow(orderRedisTemplate.getOrder(devicePile.getCode(), port.getPort(), OrderEnum.Status.NotStarted));

                    //修复订单状态
                    if (notStartOrder != null) {
                        ebOrderManager.fixNotStartOrder(notStartOrder, port);
                    }
                }

                //记录订单实时数据
                Order order = ebOrderManager.getChargingOrder(devicePile.getCode(), port.getPort());
                log.debug("deviceHeart order:{}", order);
                if (order != null) {

                    orderRedisTemplate.setOrder(order.getDeviceCode(),order.getPort(),OrderEnum.Status.Charging,order.getChargeOrderId());

                    //刷卡订单，补充开始电能数值
                    EbOrder ebOrder = ebOrderService.getRow("charge_order_id", order.getChargeOrderId());
                    if (ebOrder != null && StringUtil.isEmpty(ebOrder.getBeginEnergy())) {
                        ebOrder.setBeginEnergy(port.getEnergy());
                        ebOrderService.updateRow(ebOrder);
                    }

                    //欣华设备为0时，需要更改
                    if (DeviceProtocolEnum.XH_TCP_10.getKey().equals(devicePile.getProtocol()) && ebOrder != null && StringUtil.toInt(ebOrder.getBeginEnergy()) == 0) {
                        ebOrder.setBeginEnergy(port.getEnergy());
                        ebOrderService.updateRow(ebOrder);
                    }

                    if (ebOrder != null) {
                        OrderPower item = new OrderPower();
                        item.setComId(order.getComId());
                        item.setChargeOrderId(order.getChargeOrderId());
                        item.setCreateTime(new Date());
                        item.setEnergy(port.getEnergy());
                        item.setPower(port.getPower());
                        item.setCurrent(port.getCurrent());
                        item.setVoltage(StringUtil.toDouble(port.getVoltage()));
                        item.setStatus(port.getState() + "");
                        item.setTime(ebOrderManager.getOrderChargeSeconds(order, new Date()));
                        orderPowerService.saveRow(item);
                    }

                   // ebOrderManager.updateChargeSecondsAndPower(order, port.getDuration(), port.getPower().intValue());

                    //log.debug("body: power:{}-{}", StringUtil.getTrim(order.get("charge_power")), socket.getPower());
                    if (StringUtil.equals(ebOrder.getFeeType(), OrderEnum.FeeType.Time.name())) {
                        boolean isFreeOrder = ebOrderManager.isFreeOrder(order);

                        //功率变大，调整订单时间
                        if (ebOrder != null && port.getPower() > StringUtil.toInt(ebOrder.getEndPower()) && !isFreeOrder) {
                            if (DeviceProtocolEnum.XH_TCP_10.getKey().equals(devicePile.getProtocol())) {
                                if (ebOrder.getTempPowerNum() <= 5) {//当小于5次时，不跳档
                                    ebOrderManager.saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EB.ChangeMaxPower, new Date(),
                                            JSONUtil.toJSONString(port), "功率变大记录数：" + ebOrder.getTempPowerNum());

                                    //当为零时，第一次记录
                                    if (ebOrder.getChargePower() == 0) {
                                        ebOrder.setChargePower(port.getPower().intValue());
                                    }

                                    ebOrder.setTempPowerNum(ebOrder.getTempPowerNum() + 1);
                                    ebOrder.setTempMaxPower(port.getPower().intValue());
                                    ebOrderService.updateRow(ebOrder);
                                    return;
                                }
                            }

                            try {
                                //仅修改为最大功率和功率档位
                                ebOrderManager.adjustOrderPower(order, ebOrder,port.getPower().intValue(), port.getDuration(), port);
                            } catch (Exception ex) {
                                log.error("", ex);
                            }
                        }

                        //实时计费，如果余额用户则停止充电
                        ebOrderManager.adjustOrderTime(order,ebOrder,port);


                    }else if(StringUtil.equals(ebOrder.getFeeType(), OrderEnum.FeeType.Energy.name())){
                        ebOrderManager.adjustOrderEnergy(order, port.getEnergy());
                    }

                    //更新订单最大功率
                    ebOrderManager.adjustOrderMaxPower(order, port.getPower().intValue());

                    if (orderRedisTemplate.hasChargeFull(order.getChargeOrderId(),StringUtil.toInt(port.getPower()))) {
                        try {
                            ebOrderManager.fullStopCharge(order.getOrderNo());
                        } catch (Exception ex) {
                            log.error("平台判断充满自停失败：", ex);
                        }
                    }

                    //平台判断计时结束:当设备不上报计时结束超过2分钟，平台自己结束
                    if (ebOrderManager.isTimeEnd(order)) {
                        try {
                            ebOrderManager.timeEndStopCharge(order.getOrderNo());
                        } catch (Exception ex) {
                            log.error("平台判断充满自停失败：", ex);
                        }
                    }
                } else{
                    //没有订单的正在充电的充电口直接停止掉
                    RpcEBDeviceService rpcEBDeviceService = serviceFactory.getRpcEBDeviceService(protocol);
                    if(rpcEBDeviceService == null){
                        throw new ServiceException("设备请重新上电后再尝试！");
                    }
                    //停充
                    rpcEBDeviceService.reqStopCharge(OrderUtil.getOrderNo(),new DeviceKey(devicePile.getImei()),port.getPort());
                }
            }
        }

    }

    public void sendTTS(String imei, String text){
        Pile devicePile = pileService.getRow("imei",imei);
        if (devicePile == null)
            return;

        serviceFactory.getRpcEBDeviceService(devicePile.getProtocol()).reqPlayTTS(IdUtils.getPrimaryKey(), new DeviceKey(imei), text);

    }
}
